home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / tw14w12s.zoo / tw14w12s / util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-06  |  21.3 KB  |  1,054 lines

  1. /*
  2.  * Copyright 1992 Eric R. Smith. All rights reserved.
  3.  * Redistribution is permitted only if the distribution
  4.  * is not for profit, and only if all documentation
  5.  * (including, in particular, the file "copying")
  6.  * is included in the distribution in unmodified form.
  7.  * THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
  8.  * EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
  9.  * FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
  10.  * RISK.
  11.  */
  12. #include "xgem.h"
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include <ctype.h>
  16. #include "toswin_w.h"
  17. #include "twdefs.h"
  18. #include "twproto.h"
  19.  
  20. extern char *read_scrap();
  21. extern void write_scrap();
  22.  
  23. /* shift key states */
  24. #define KLSHIFT    0x1
  25. #define KRSHIFT    0x2
  26. #define KCTRL    0x4
  27. #define KALT    0x8
  28. #define KANY    (0xf)
  29.  
  30. /* what to add at the end of lines */
  31. #define CR    1
  32. #define LF    2
  33. #define CRLF    3
  34. #ifdef NONE
  35. #undef NONE
  36. #endif
  37.  
  38. #define NONE    0
  39. int paste_options = CR;
  40.  
  41. /* how to cut lines */
  42. #define STRIPBLANKS    1
  43. #define OBEYLINES    2
  44. int cut_options = STRIPBLANKS;
  45.  
  46.  
  47. void
  48. setcutoptions()
  49. {
  50.     int xclip, yclip, wclip, hclip;
  51.     int ret;
  52.  
  53.     cutdialog[ADDCRLF].ob_state = 
  54.     cutdialog[ADDLF].ob_state =
  55.     cutdialog[ADDCR].ob_state = 
  56.     cutdialog[ADDNONE].ob_state = NORMAL;
  57.  
  58.     switch(paste_options) {
  59.     case CR:
  60.         ret = ADDCR; break;
  61.     case LF:
  62.         ret = ADDLF; break;
  63.     case CRLF:
  64.         ret = ADDCRLF; break;
  65.     default:
  66.         ret = ADDNONE; break; /* WWA - was "NONE" */
  67.     }
  68.     cutdialog[ret].ob_state = SELECTED;
  69.  
  70.     cutdialog[STRIPEOL].ob_state = (cut_options & STRIPBLANKS) ? SELECTED :
  71.             NORMAL;
  72.     cutdialog[OBEYEOL].ob_state = (cut_options & OBEYLINES) ? SELECTED :
  73.             NORMAL;
  74.  
  75.     wind_update(1);
  76.     form_center(cutdialog, &xclip, &yclip, &wclip, &hclip);
  77.     form_dial(FMD_START, 0, 0, 32, 32, xclip, yclip, wclip, hclip);
  78.     if (win_flourishes)
  79.         form_dial(FMD_GROW, 0, 0, 32, 32, xclip, yclip, wclip, hclip);
  80.     objc_draw(cutdialog, 0, 2, xclip, yclip, wclip, hclip);
  81.     ret = form_do(cutdialog,  0);
  82.     if (win_flourishes)
  83.         form_dial(FMD_SHRINK, 0, 0, 32, 32, xclip, yclip, wclip, hclip);
  84.     form_dial(FMD_FINISH, 0, 0, 32, 32, xclip, yclip, wclip, hclip);
  85.     wind_update(0);
  86.  
  87.     cutdialog[ret].ob_state = NORMAL;
  88.     if (ret == EDOK) {
  89.         cut_options = NONE;
  90.         if (cutdialog[STRIPEOL].ob_state == SELECTED)
  91.             cut_options |= STRIPBLANKS;
  92.         if (cutdialog[OBEYEOL].ob_state == SELECTED)
  93.             cut_options |= OBEYLINES;
  94.  
  95.         if (cutdialog[ADDCR].ob_state == SELECTED)
  96.             paste_options = CR;
  97.         else if (cutdialog[ADDLF].ob_state == SELECTED)
  98.             paste_options = LF;
  99.         else if (cutdialog[ADDCRLF].ob_state == SELECTED)
  100.             paste_options = CRLF;
  101.         else
  102.             paste_options = NONE;
  103.  
  104.     }
  105. }
  106.  
  107. /* unselect all text in the indicated window */
  108.  
  109. void
  110. unselect(t)
  111.     TEXTWIN *t;
  112. {
  113.     int i, j;
  114.  
  115.     for (i = 0; i < t->maxy; i++)
  116.         for (j = 0; j < t->maxx; j++) {
  117.             if (t->cflag[i][j] & CSELECTED) {
  118.                 t->cflag[i][j] &= ~CSELECTED;
  119.                 t->cflag[i][j] |= CTOUCHED;
  120.                 t->dirty[i] |= SOMEDIRTY;
  121.                 }
  122.         }
  123.     refresh_textwin(t);
  124. }
  125.  
  126. /* cut selected text from a window */
  127.  
  128. char *cliptext = 0;
  129.  
  130. void
  131. cut(w)
  132.     WINDOW *w;
  133. {
  134.     TEXTWIN *t;
  135.     int i, j, numchars, numlines;
  136.     int linedone;
  137.     int needcrlf;
  138.     char *s, c;
  139.  
  140.     if (w->wtype != TEXT_WIN) return;
  141.     t = w->extra;
  142.  
  143.     if (cliptext) {
  144.         free(cliptext);
  145.         cliptext = 0;
  146.     }
  147.  
  148.     numchars = numlines = 0;
  149.     for (i = 0; i < t->maxy; i++) {
  150.         linedone = 0;
  151.         for (j = 0; j < t->maxx; j++) {
  152.             if (t->cflag[i][j] & CSELECTED) {
  153.                 numchars++;
  154.                 if (!linedone) {
  155.                     numlines++;
  156.                     linedone = 1;
  157.                 }
  158.             }
  159.         }
  160.     }
  161.     if (!numchars) {
  162.         form_alert(1, AlertStrng(NOTEXT));
  163.         return;
  164.     }
  165. /*
  166.  * The cut strategy is a little complicated, but here it is:
  167.  * A "line" is a continuous stream of characters. If the "Obey Lines"
  168.  * option is set, lines always end at end-of-line; otherwise, they
  169.  * end at eol only if there are 2 or more spaces after them.
  170.  * If "Strip Blanks" is set, then any trailing blanks are deleted.
  171.  */
  172.     cliptext = malloc(numchars+numlines+numlines+1);
  173.     if (!cliptext) {
  174.         form_alert(1, AlertStrng(NOMEM));
  175.         return;
  176.     }
  177.  
  178.     s = cliptext;
  179.  
  180.     needcrlf = 0;
  181.     for (i = 0; i < t->maxy; i++) {
  182.         linedone = 0;
  183.         for (j = 0; j < t->maxx; j++) {
  184.             if (t->cflag[i][j] & CSELECTED) {
  185.                 c = t->data[i][j];
  186.                 if (!c) c = ' ';
  187.                 *s++ = c;
  188.                 needcrlf = 1;
  189.                 if ( (cut_options & OBEYLINES) ||
  190.  
  191.                     /* WWA - this was incorrect */
  192.                     /* (j < t->maxy-2) || */
  193.                      ((j > 0) &&
  194.  
  195.                      ((c == ' ') && t->data[i][j-1] == ' ')))
  196.                     linedone = 1;
  197.                 else
  198.                     linedone = 0;
  199.             }
  200.         }
  201.         if (linedone) {
  202.             if (cut_options & STRIPBLANKS) {
  203.                 while (s > cliptext && s[-1] == ' ')
  204.                     --s;
  205.             }
  206.             *s++ = '\r'; *s++ = '\n';
  207.             needcrlf = 0;
  208.         }
  209.     }
  210.  
  211. #ifndef WWA_X_SELECT
  212. /* tie off cliptext */
  213.     if (needcrlf) {
  214.         *s++ = '\r'; *s++ = '\n';
  215.     }
  216. #endif
  217.     *s++ = 0;
  218.  
  219. #ifndef WWA_X_SELECT
  220.     unselect(t);
  221. #endif
  222. }
  223.  
  224. /* paste text into a window */
  225.  
  226. void
  227. paste(w)
  228.     WINDOW *w;
  229. {
  230.     char *s;
  231.     int c;
  232.  
  233.     if (!cliptext) {
  234.         form_alert(1, AlertStrng(NOCUT));
  235.         return;
  236.     }
  237.     for (s = cliptext; *s; s++) {
  238.         c = *(unsigned char *)s;
  239.         if (c == '\r' && s[1] == '\n') {
  240.             s++;
  241.             switch(paste_options) {
  242.             case CRLF:
  243.                 (*w->keyinp)(w, '\r', 0);
  244.             case LF:
  245.                 (*w->keyinp)(w, '\n', 0);
  246.                 break;
  247.             case CR:
  248.                 (*w->keyinp)(w, '\r', 0);
  249.                 break;
  250.             case NONE:
  251.                 break;
  252.             }
  253.         } else 
  254.             (*w->keyinp)(w, c, 0);
  255.     }
  256. }
  257.  
  258. void
  259. redraw_screen(x, y, w, h)
  260.     int x, y, w, h;
  261. {
  262.     form_dial(0, x, y, w, h, x, y, w, h);
  263.     form_dial(3, x, y, w, h, x, y, w, h);
  264. }
  265.  
  266. /* cut text from the desktop */
  267.  
  268. void
  269. cut_from_desk(x, y)
  270.     int x, y;
  271. {
  272.     int i;
  273.     int width, height, x1, y1, x2, y2, dummy;
  274.     WINDOW *w;
  275.  
  276.     i = objc_find(deskobj, 0, 1, x, y);
  277.     if (i != CLIPICN) {
  278.         if (gl_topwin && gl_topwin->wtype == TEXT_WIN)
  279.             unselect(gl_topwin->extra);
  280.         return;
  281.     }
  282.     width = deskobj[i].ob_width; height = deskobj[i].ob_height;
  283.     objc_offset(deskobj, i, &x1, &y1);
  284.  
  285. /* drag the icon around */
  286.     wind_update(BEG_MCTRL);
  287.     graf_mouse(FLAT_HAND, 0L);
  288.     graf_dragbox(width, height, x1, y1, xdesk, ydesk, wdesk, hdesk,
  289.         &x2, &y2);
  290.  
  291.     graf_mkstate(&x, &y, &dummy, &dummy);
  292.     graf_mouse(ARROW, 0L);
  293.     wind_update(END_MCTRL);
  294.  
  295. /* did we actually move anywhere? */
  296.     if (x >= x1 && x <= x1+width && y >= y1 && y <= y1+height) {
  297.         return;
  298.     }
  299.     w = find_window(x, y);
  300.     if (w && w->wtype == TEXT_WIN) {
  301.         if (cliptext)
  302.             free(cliptext);
  303.  
  304.         cliptext = read_scrap("SCRAP.TXT");
  305.         if (!cliptext) {
  306.             form_alert(1, AlertStrng(SCRAPDAT));
  307.             return;
  308.         }
  309.         paste(w);
  310. #if 0
  311.     } else {        /* just move the icon */
  312.         hide_mouse();
  313.         deskobj[i].ob_x += x2 - x1;
  314.         deskobj[i].ob_y += y2 - y1;
  315.         redraw_screen(x1, y1, width, height);
  316.         redraw_screen(x2, y2, width, height);
  317.         show_mouse();
  318. #endif
  319.     }
  320. }
  321.  
  322. /* paste text onto the desktop */
  323.  
  324. void
  325. paste_to_desk(x, y)
  326.     int x, y;
  327. {
  328.     int i;
  329.     int x1, y1;
  330.     WINDOW *w;
  331.  
  332.     w = find_window(x, y);
  333.     i = objc_find(deskobj, 0, 1, x, y);
  334.     if (i == CLIPICN) {
  335.         objc_offset(deskobj, CLIPICN, &x1, &y1);
  336.         objc_change(deskobj, CLIPICN, 0, xdesk, ydesk, wdesk, hdesk,
  337.             SELECTED, 0);
  338.         if (w == toolwindow) {
  339.             redraw_window(toolwindow, x1, y1,
  340.                 deskobj[i].ob_width, deskobj[i].ob_height);
  341.         }
  342.         write_scrap("SCRAP.TXT", cliptext, (int)strlen(cliptext));
  343.         objc_change(deskobj, CLIPICN, 0, xdesk, ydesk, wdesk, hdesk,
  344.             NORMAL, 0);
  345.         if (w == toolwindow) {
  346.             redraw_window(toolwindow, x1, y1,
  347.                 deskobj[i].ob_width, deskobj[i].ob_height);
  348.         }
  349.     }
  350. }
  351.  
  352. static void
  353. lightbox(plin, numpoints)
  354.     int *plin;
  355.     int numpoints;
  356. {
  357.     static int vtbl[4] = { 0x5555, 0xaaaa, 0xaaaa, 0x5555 };
  358.     static int htbl[2] = { 0x5555, 0xaaaa };
  359.     int style, *linexy, i;
  360.     int attrib[6];
  361.  
  362.     vql_attribute(vdi_handle, attrib);
  363.  
  364.     vsl_color(vdi_handle, 1);
  365.  
  366.     for (i = 1; i < numpoints; i++) {
  367.         if (plin[0] == plin[2])
  368.             style = vtbl[(plin[0] & 1) | ((plin[1] & 1) << 1)];
  369.         else {
  370.             linexy = (plin[0] < plin[2]) ? plin : plin+2;
  371.             style = htbl[ linexy[1] & 1 ];
  372.         }
  373.         vsl_udsty(vdi_handle, style);
  374.         vsl_type(vdi_handle, 7);
  375.         v_pline(vdi_handle, 2, plin);
  376.         plin += 2;
  377.     }
  378.  
  379.     vsl_type(vdi_handle, attrib[0]);
  380.     vsl_color(vdi_handle, attrib[1]);
  381. }
  382.  
  383. void
  384. hot_dragbox(plin, numpoints, lastx, lasty)
  385.     int *plin;
  386.     int numpoints;
  387.     int *lastx, *lasty;
  388. {
  389.     int boxx, boxy;
  390.     int msx, msy, mbutton, dummy, event;
  391.     int newx, newy;
  392.     int oldbx, oldby;
  393.     int deltax, deltay;
  394.     int width, height;
  395.     int clipx, clipy, clipw, cliph;    /* box holding the clipboard
  396.                            icon */
  397.  
  398.     int inclip = 0;
  399.     int i;
  400.  
  401. /* find the biggest rectangle that will enclose the region */
  402.     boxx = plin[0]; boxy = plin[1];
  403.     clipx = boxx; clipy = boxy;
  404.  
  405.     for (i = 2; i < numpoints + numpoints; i += 2) {
  406.         if (plin[i] < boxx) boxx = plin[i];
  407.         if (plin[i] > clipx) clipx = plin[i];
  408.         if (plin[i+1] < boxy) boxy = plin[i+1];
  409.         if (plin[i+1] > clipy) clipy = plin[i+1];
  410.     }
  411.     width = clipx - boxx + 1;
  412.     height = clipy - boxy + 1;
  413.  
  414.     set_wrmode(3);        /* XOR */
  415.  
  416.     if (showtools) {
  417.         objc_offset(deskobj, CLIPICN, &clipx, &clipy);
  418.         clipw = deskobj[CLIPICN].ob_width;
  419.         cliph = deskobj[CLIPICN].ob_height;
  420.  
  421.         graf_mkstate(&msx, &msy, &mbutton, &dummy);
  422.         if (msx >= clipx && msx < clipx+clipw && 
  423.             msy >= clipy && msy < clipy+cliph)
  424.             inclip = 1;
  425.     } else {
  426.         graf_mkstate(&msx, &msy, &mbutton, &dummy);
  427.         clipx = clipy = clipw = cliph = -1;
  428.         inclip = 0;
  429.     }
  430.  
  431.     hide_mouse();
  432.     lightbox(plin, numpoints);
  433.     show_mouse();
  434.  
  435.     reset_clip();
  436.     for(;;) {
  437.         oldbx = boxx; oldby = boxy;
  438.         event = evnt_multi(MU_BUTTON|MU_M1|MU_M2,
  439.             1, 0x0001, 0x0000,
  440.             1, msx, msy, 1, 1,
  441.             inclip, clipx, clipy, clipw, cliph,
  442.             0L, 0L,
  443.             &newx, &newy, &mbutton, &dummy,
  444.             &dummy, &dummy);
  445.         if (showtools && (event & MU_M2)) {
  446.             inclip = !inclip;
  447.             hide_mouse();
  448.             lightbox(plin, numpoints);
  449.             objc_change(deskobj, CLIPICN, 0, clipx, clipy, clipw,
  450.                 cliph, inclip ? SELECTED : NORMAL, 0);
  451.             redraw_window(toolwindow, clipx, clipy,
  452.                 clipw, cliph);
  453. /* note: redraw_window turns the mouse back on and changes the clipping
  454.  * rectangle
  455.  */
  456.             reset_clip();
  457.             hide_mouse();
  458.             lightbox(plin, numpoints);
  459.             show_mouse();
  460.         }
  461.         if (event & MU_M1) {
  462.             boxx = boxx + (newx - msx);
  463.             if (boxx < xdesk)
  464.                 boxx = xdesk;
  465.             else if (boxx + width > xdesk + wdesk)
  466.                 boxx = xdesk+wdesk - width;
  467.             boxy = boxy + (newy - msy);
  468.             if (boxy < ydesk)
  469.                 boxy = ydesk;
  470.             else if (boxy + height > ydesk + hdesk)
  471.                 boxy = ydesk + hdesk - height;
  472.             if (oldbx != boxx || oldby != boxy) {
  473.                 hide_mouse();
  474.                 lightbox(plin, numpoints);
  475.                 deltax = boxx - oldbx;
  476.                 deltay = boxy - oldby;
  477.                 for (i = 0; i < numpoints + numpoints; i += 2) {
  478.                     plin[i] += deltax;
  479.                     plin[i+1] += deltay;
  480.                 }
  481.                 lightbox(plin, numpoints);
  482.                 oldbx = boxx;
  483.                 oldby = boxy;
  484.                 show_mouse();
  485.             } 
  486.         }
  487.         msx = newx;
  488.         msy = newy;
  489.         if (event & MU_BUTTON)
  490.             break;
  491.     }
  492.     hide_mouse();
  493.     lightbox(plin, numpoints);
  494.     show_mouse();
  495.     *lastx = boxx;
  496.     *lasty = boxy;
  497. }
  498.  
  499. /*
  500.  * debounce the mouse, so that we can distinguish single-clicks, double-clicks,
  501.  * and drags
  502.  */
  503.  
  504. #ifndef WWA_X_SELECT
  505. static int
  506. debounce(time, x, y, kshift, buttons)
  507.     long time;
  508.     int *x, *y, *kshift, *buttons;
  509. {
  510.     int clicks = 0;
  511.     int event, dummy;
  512.  
  513.     if (time > 0) {
  514.         event = evnt_multi(MU_BUTTON | MU_TIMER,
  515.             0x0102, 0x0003, *buttons,
  516.             0, 0, 0, 0, 0,
  517.             0, 0, 0, 0, 0,
  518.             (void *)0,
  519.             time,        /* milliseconds */
  520.             x, y, buttons, kshift,
  521.             &dummy, &clicks);
  522.     } else {
  523.         event = MU_TIMER;
  524.     }
  525.     graf_mkstate(x, y, buttons, kshift);
  526.  
  527.     return (event & MU_BUTTON) ? clicks : 1;
  528. }
  529. #endif
  530.  
  531. #ifdef GLOBAL_APPL_MENUS
  532.  
  533. void
  534. togglemenu()
  535. {
  536.     WINDOW *w = gl_topwin;
  537.     ENTRY *e;
  538.  
  539.     for (e = globalmenu->contents; e; e = e->next) {
  540.         if (e->func == togglemenu) {
  541.             break;
  542.         }
  543.     }
  544.  
  545.     if (!sys_menu) {
  546.         sys_menu = 1;
  547.         appl_menus = 0;
  548.         show_menu(sysbar);
  549.     } else {
  550.         appl_menus = !appl_menus;
  551.         if (w && w->wtype == TEXT_WIN) {
  552.             if (w->menu && appl_menus) {
  553.                 sys_menu = 0;
  554.                 show_menu(w->menu);
  555.             }
  556.         }
  557.     }
  558.     if (e) {
  559.         if (appl_menus)
  560.             check_entry(globalmenu, e);
  561.         else
  562.             uncheck_entry(globalmenu, e);
  563.     }
  564. }
  565.  
  566. #endif
  567.  
  568. static void pixpoint __PROTO((TEXTWIN *, int, int, int *, int *));
  569. static void dragtext __PROTO((TEXTWIN *, int, int));
  570. static void selectfrom __PROTO((TEXTWIN *, int, int, int, int));
  571. #ifdef WWA_X_SELECT
  572. static int select __PROTO((TEXTWIN *, int, int, int));
  573. #else
  574. static void select __PROTO((TEXTWIN *, int, int, int));
  575. #endif
  576.  
  577. static void
  578. pixpoint(t, col, row, xp, yp)
  579.     TEXTWIN *t;
  580.     int col, row, *xp, *yp;
  581. {
  582.     int x, y;
  583.     WINDOW *w = t->win;
  584.  
  585.     char2pixel(t, col, row, &x, &y);
  586.  
  587.     if (x < w->wi_x)
  588.         x = w->wi_x;
  589.     else if (x > w->wi_x + w->wi_w)
  590.         x = w->wi_x + w->wi_w;
  591.  
  592.     if (y < w->wi_y)
  593.         y = w->wi_y;
  594.     else if (y > w->wi_y + w->wi_h)
  595.         y = w->wi_y + w->wi_h;
  596.  
  597.     *xp = x;
  598.     *yp = y;
  599. }
  600.  
  601. static void
  602. dragtext(t, x, y)
  603.     TEXTWIN *t;
  604.     int x, y;
  605. {
  606.     static int plin[20];
  607.     int numpoints;
  608.     int i, j;
  609.     int firstx, firsty, lastx, lasty;
  610.     WINDOW *newwin, *w = t->win;
  611.     int buttons, kshift;
  612.  
  613.     firstx = firsty = lastx = lasty = -1;
  614.     /* find edges of region */
  615.     for (j = 0; j < t->maxy; j++) {
  616.         for (i = 0; i < t->maxx; i++) {
  617.             if (t->cflag[j][i] & CSELECTED) {
  618.                 if (firstx == -1) {
  619.                     firstx = i;
  620.                     firsty = j;
  621.                 }
  622.                 lastx = i;
  623.                 lasty = j;
  624.             }
  625.         }
  626.     }
  627.  
  628.     if (firstx == -1) return;
  629.  
  630.     pixpoint(t, firstx, firsty, &plin[0], &plin[1]);
  631.  
  632.     if (firsty == lasty) {
  633.         numpoints = 5;
  634.         pixpoint(t, lastx+1, firsty, &plin[2], &plin[3]);
  635.         plin[4] = plin[2]; plin[5] = plin[3] + t->cheight;
  636.         if (plin[5] > w->wi_y + w->wi_h)
  637.             plin[5] = w->wi_y + w->wi_h;
  638.         plin[6] = plin[0]; plin[7] = plin[5];
  639.         plin[8] = plin[0]; plin[9] = plin[1];
  640.     } else {
  641.         numpoints = 9;
  642.         pixpoint(t, t->maxx, firsty, &plin[2], &plin[3]);
  643.         pixpoint(t, t->maxx, lasty, &plin[4], &plin[5]);
  644.         pixpoint(t, lastx+1, lasty, &plin[6], &plin[7]);
  645.         plin[8] = plin[6]; plin[9] = plin[7] + t->cheight;
  646.         if (plin[9] > w->wi_y + w->wi_h)
  647.             plin[9] = w->wi_y + w->wi_h;
  648.         plin[10] = w->wi_x; plin[11] = plin[9];
  649.         pixpoint(t, 0, firsty+1, &plin[12], &plin[13]);
  650.         plin[14] = plin[0]; plin[15] = plin[13];
  651.         plin[16] = plin[0]; plin[17] = plin[1];
  652.     }
  653.  
  654. /* drag text */
  655.     wind_update(BEG_MCTRL);
  656.     graf_mouse(FLAT_HAND, 0L);
  657.     hot_dragbox(plin, numpoints, &x, &y);
  658.     graf_mkstate(&x, &y, &buttons, &kshift);
  659.     graf_mouse(ARROW, 0L);
  660.     wind_update(END_MCTRL);
  661. /* did we actually move anywhere? */
  662.     newwin = find_window(x, y);
  663.     if (newwin == t->win) {
  664.         pixel2char(t, x, y, &x, &y);
  665.         if (t->cflag[y][x] & CSELECTED)
  666.             return;
  667.     }
  668.  
  669. /* yes, we did move; do a cut and paste */
  670.     cut(w);
  671.     if (newwin) {
  672.         if (newwin->wtype == TEXT_WIN)
  673.             paste(newwin);
  674.         else
  675.             paste_to_desk(x, y);
  676.     } else {
  677.         form_alert(1, AlertStrng(NOTDESK)); 
  678.     }
  679. }
  680.  
  681. static void
  682. selectfrom(t, x1, y1, x2, y2)
  683.     TEXTWIN *t;
  684.     int x1, y1, x2, y2;
  685. {
  686.     int i, j;
  687.     int first, last;
  688.  
  689. /* first, normalize coordinates */
  690.     if ( (y1 > y2) || (y1 == y2 && x1 > x2) ) {
  691.         i = x1; j = y1;
  692.         x1 = x2; y1 = y2;
  693.         x2 = i; y2 = j;
  694.     }
  695.  
  696.     for (j = 0; j <= y1; j++) {
  697.         last = (j == y1) ? x1 : t->maxx;
  698.         for (i = 0; i < last; i++) {
  699.             if (t->cflag[j][i] & CSELECTED) {
  700.                 t->cflag[j][i] &= ~CSELECTED;
  701.                 t->cflag[j][i] |= CTOUCHED;
  702.                 t->dirty[j] |= SOMEDIRTY;
  703.             }
  704.         }
  705.     }
  706.     for (j = y1; j <= y2; j++) {
  707.         first = (j == y1) ? x1 : 0;
  708.         last = (j == y2) ? x2+1 : t->maxx;
  709.         for (i = first; i < last; i++) {
  710.             if (!(t->cflag[j][i] & CSELECTED)) {
  711.                 t->cflag[j][i] |= (CTOUCHED|CSELECTED);
  712.                 t->dirty[j] |= SOMEDIRTY;
  713.             }
  714.         }
  715.     }
  716.     for (j = y2; j < t->maxy; j++) {
  717.         first = (j == y2) ? x2+1 : 0;
  718.         for (i = first; i < t->maxx; i++) {
  719.             if (t->cflag[j][i] & CSELECTED) {
  720.                 t->cflag[j][i] &= ~CSELECTED;
  721.                 t->cflag[j][i] |= CTOUCHED;
  722.                 t->dirty[j] |= SOMEDIRTY;
  723.             }
  724.         }
  725.     }
  726.     refresh_textwin(t);
  727. }
  728.  
  729. #ifdef WWA_X_SELECT
  730.  
  731. void release_button(b)
  732.     int b;
  733. {
  734.     int event, dummy, msx, msy, mbutton;
  735.  
  736.     wind_update(BEG_MCTRL);
  737.  
  738.     for(;;) {
  739.         event = evnt_multi(MU_BUTTON, 1, b, 0,
  740.             1, 0, 0, 0, 0,
  741.             0, 0, 0, 0, 0,
  742.             0L, 0L,
  743.             &msx, &msy, &mbutton, &dummy,
  744.             &dummy, &dummy);
  745.         if (event & MU_BUTTON)
  746.             break;
  747.     }
  748.  
  749.     wind_update(END_MCTRL);
  750. }
  751.  
  752. int CharClass(ch)
  753.     char ch;
  754. {
  755.     /* Hard wire */
  756.  
  757.     /* Filename/emailaddres/identifier class */
  758.     if (isalnum(ch) || ch=='/' || ch=='.' || ch=='_' || ch=='@')
  759.         return 1;
  760.     else if (iswhite(ch))
  761.         return 2;
  762.     else
  763.         return 1000+ch; /* One class per character */
  764. }
  765.  
  766. int /* 0==none selected, 1==non-line selected 2==line selected */
  767. expand_selection(t, curcol, currow, kshift)
  768.     TEXTWIN *t;
  769.     int curcol, currow, kshift;
  770. {
  771.     int curclass=CharClass(t->data[currow][curcol]);
  772.  
  773.     refresh_textwin(t);
  774.  
  775.     if (t->cflag[currow][curcol]&CSELECTED) {
  776.         int second=1;
  777.         if (curcol>0) {
  778.             if (t->cflag[currow][curcol-1]&CSELECTED
  779.             && CharClass(t->data[currow][curcol-1])==curclass) {
  780.                 second=0;
  781.             }
  782.         }
  783.         if (curcol<t->maxx) {
  784.             if (t->cflag[currow][curcol+1]&CSELECTED
  785.             && CharClass(t->data[currow][curcol+1])==curclass) {
  786.                 second=0;
  787.             }
  788.         }
  789.         if (second) {
  790.             /* Second click - class */
  791.  
  792.             int lcol=curcol;
  793.             int rcol=curcol;
  794.  
  795.             while (lcol>0 && CharClass(t->data[currow][lcol])==curclass) {
  796.                 lcol--;
  797.             }
  798.             if (CharClass(t->data[currow][lcol])!=curclass)
  799.                 lcol++;
  800.  
  801.             while (rcol<t->maxx && CharClass(t->data[currow][rcol])==curclass) {
  802.                 rcol++;
  803.             }
  804.             if (CharClass(t->data[currow][rcol])!=curclass)
  805.                 rcol--;
  806.  
  807.             selectfrom(t, lcol, currow, rcol, currow);
  808.         } else {
  809.             /* Third click - line */
  810.             if (t->cflag[currow][0]&CSELECTED && t->cflag[currow][t->maxx-1]&CSELECTED) {
  811.                 /* Fourth click - nothing */
  812.                 unselect(t);
  813.                 return 0;
  814.             } else {
  815.                 selectfrom(t, 0, currow, t->maxx, currow);
  816.                 return 2;
  817.             }
  818.         }
  819.     } else {
  820.         /* First click - character */
  821.         selectfrom(t, curcol, currow, curcol, currow);
  822.     }
  823.  
  824.     return 1;
  825. }
  826. #endif
  827.  
  828. #ifdef WWA_X_SELECT
  829. int
  830. #else
  831. void
  832. #endif
  833. select(t, curcol, currow, kshift)
  834.     TEXTWIN *t;
  835.     int curcol, currow, kshift;
  836. {
  837.     WINDOW *v = t->win;
  838.     int x, y, firstx, firsty;
  839.     int event, dummy, msx, msy, mbutton;
  840.     int anchorcol, anchorrow;
  841.     short *WIDE = t->cwidths;
  842.     int cboxw;
  843.  
  844.     refresh_textwin(t);
  845.  
  846. /* shift+select adds to existing text; regular select replaces */
  847.     anchorrow = currow; anchorcol = curcol;
  848.  
  849.     if (kshift & 3) {
  850.         for (y = 0; y < t->maxy; y++)
  851.             for (x = 0; x < t->maxx; x++) {
  852.                 if (t->cflag[y][x] & CSELECTED) {
  853.                     anchorrow = y;
  854.                     anchorcol = x;
  855.                     if (y < currow ||
  856.                         (y == currow && x < curcol)) {
  857.                         goto foundselect;
  858.                     }
  859.                         
  860.                 }
  861.             }
  862.     } else {
  863.         unselect(t);
  864.     }
  865.  
  866. foundselect:
  867.  
  868.     char2pixel(t, curcol, currow, &x, &y);
  869.     firstx = msx = x; firsty = msy = y;
  870.  
  871.     wind_update(BEG_MCTRL);
  872.     graf_mouse(POINT_HAND, 0L);
  873.  
  874.     selectfrom(t, anchorcol, anchorrow, curcol, currow);
  875.  
  876.     cboxw = t->cmaxwidth;
  877.     for(;;) {
  878.         if (WIDE)
  879.             cboxw = WIDE[t->data[currow][curcol]];
  880.  
  881.         event = evnt_multi(MU_M1 | MU_BUTTON, 
  882.             0x101, 0x0003, 0x0001,
  883.             1, x, y, cboxw, t->cheight,
  884.             0, 0, 0, 0, 0,
  885.             0L, 0L,
  886.             &msx, &msy, &mbutton, &dummy,
  887.             &dummy, &dummy);
  888.         if (event & MU_M1) {
  889.             if (msx < v->wi_x)
  890.                 msx = v->wi_x;
  891.             else if (msx >= v->wi_x + v->wi_w)
  892.                 msx = v->wi_x + v->wi_w - 1;
  893.             if (msy < v->wi_y)
  894.                 msy = v->wi_y;
  895.             else if (msy >= v->wi_y + v->wi_h)
  896.                 msy = v->wi_y + v->wi_h - 1;
  897.             pixel2char(t, msx, msy, &curcol, &currow);
  898.             char2pixel(t, curcol, currow, &x, &y);
  899.             selectfrom(t, anchorcol, anchorrow, curcol, currow);
  900.         }
  901.         if (event & MU_BUTTON)
  902.             break;
  903.     }
  904.  
  905.     graf_mouse(ARROW, 0L);
  906.     wind_update(END_MCTRL);
  907.  
  908.     if ( ((msx - firstx) < 3) && ((msx - firstx) > -3) &&
  909.          ((msy - firsty) < 3) && ((msy - firsty > -3)) ) {
  910.         unselect(t);
  911. #ifdef WWA_X_SELECT
  912.         return 0;
  913. #else
  914.         return;
  915. #endif
  916.     }
  917.  
  918. #ifdef WWA_X_SELECT
  919.     return 1;
  920. #else
  921.     return;
  922. #endif
  923. }
  924.  
  925. #define BOXSIZE 8
  926.  
  927. int
  928. win_ctrl(v, x, y)
  929.     WINDOW *v;
  930.     int x, y;
  931. {
  932.     int wx, wy, ww, wh;
  933.  
  934.     wind_update(BEG_MCTRL);
  935.     wind_get(v->wi_handle, WF_CURRXYWH, &wx, &wy, &ww, &wh);
  936.  
  937.     if ((x >= v->wi_x + v->wi_w - BOXSIZE) &&
  938.         (y >= v->wi_y + v->wi_h - BOXSIZE)) {
  939.         graf_mouse(POINT_HAND, 0L);
  940.         graf_rubberbox(wx, wy, 8, 8, &ww, &wh);
  941.         (*v->sized)(v, wx, wy, ww, wh);
  942.     } else if ((x >= v->wi_x + v->wi_w - BOXSIZE) &&
  943.            (y <= v->wi_y + BOXSIZE) ) {
  944.         do {
  945.             graf_mkstate(&x, &y, &ww, &wh);
  946.         } while (ww);
  947.         (*v->fulled)(v);
  948.     } else {
  949.         graf_mouse(FLAT_HAND, 0L);
  950.         graf_dragbox(ww, wh, wx, wy, xdesk, ydesk, wdesk, hdesk,
  951.             &wx, &wy);
  952.         (*v->moved)(v, wx, wy, ww, wh);
  953.     }
  954.     graf_mouse(ARROW, 0L);
  955.     wind_update(END_MCTRL);
  956.     return 1;
  957. }
  958.  
  959. int
  960. win_click(w, clicks, x, y, kshift, buttons)
  961.     WINDOW *w;
  962.     int clicks, x, y, kshift, buttons;
  963. {
  964.     TEXTWIN *t;
  965.     int x1, y1;
  966.     int ret = 0;
  967.  
  968.     t = w->extra;
  969.     
  970. #ifndef WWA_X_SELECT
  971.     if (clicks == 1) {
  972.         int i, j;
  973.         clicks = debounce(300L - gl_timer, &x, &y, &i, &j);
  974.     }
  975.  
  976.     if (clicks == 1 && buttons == 1) {  /* left click */
  977.     /* is the button still down?; if so, select some text */
  978.         graf_mkstate(&x, &y, &buttons, &kshift);
  979.         if (buttons != 1 && !(kshift&(KLSHIFT|KRSHIFT))) {
  980.     /* just a single click -- unselect old text */
  981.             unselect(t);
  982.             return 1;
  983.         }
  984. #else
  985.     if (buttons == 1) {  /* left click(s) */
  986. #endif
  987.  
  988.         if (kshift & KCTRL) {
  989.             return win_ctrl(w, x, y);
  990.         }
  991.     /* convert to character coordinates */
  992.         pixel2char(t, x, y, &x1, &y1);
  993.  
  994. #ifdef WWA_X_SELECT
  995.         if (! (t->cflag[y1][x1] & CSELECTED)) {
  996.             if (select(t, x1, y1, kshift))
  997.                 cut(w);
  998.             clicks--;
  999.         }
  1000.  
  1001.         while (clicks--) {
  1002.             switch (expand_selection(t, x1, y1, kshift)) {
  1003.              case 0:
  1004.                 /* No selection */
  1005.             break; case 1:
  1006.                 cut(w);
  1007.             break; case 2:
  1008.                 cut(w);
  1009.             }
  1010.         }
  1011.  
  1012.         release_button(1);
  1013. #else
  1014.         if (t->cflag[y1][x1] & CSELECTED) {
  1015.             dragtext(t, x1, y1);
  1016.         } else {
  1017.             select(t, x1, y1, kshift);
  1018.         }
  1019. #endif
  1020.  
  1021.         return 1;
  1022. #ifdef WWA_X_SELECT
  1023.     } else if (buttons == 2) {
  1024.         paste(w);
  1025.         release_button(2);
  1026.         ret = 1;
  1027. #endif
  1028. #ifdef GLOBAL_APPL_MENUS
  1029.     } else if (buttons == 2) {
  1030.         togglemenu();
  1031.         ret = 1;
  1032. #endif
  1033.     }
  1034.  
  1035.     return ret;
  1036. }
  1037.  
  1038. void
  1039. desk_mouse(clicks, x, y, kshift, buttons)
  1040.     int clicks, x, y, kshift, buttons;
  1041. {
  1042.     if (clicks == 1 && buttons == 1) {  /* left click */
  1043.     /* is the button still down?; if so, select some text */
  1044.         graf_mkstate(&x, &y, &buttons, &kshift);
  1045.         if (buttons == 1) {    /* still down */
  1046.             cut_from_desk(x, y);
  1047.         }
  1048. #ifdef GLOBAL_APPL_MENUS
  1049.     } else if (buttons == 2) {    /* right mouse click */
  1050.         togglemenu();
  1051. #endif
  1052.     }
  1053. }
  1054.